#!/usr/bin/python

import fm
import wx
import wx.stc as stc

# ?? s / STYLE_ID / STYLE_IDS
#	style_ids_STRING ?
from operator import isSequenceType

settings=fm.settings

settings['available_modes']=[]

def detect_file_mode_from_file_name(file):
	for mode in settings['available_modes']:
		for ext in settings['mode.'+mode+'.extensions']:
			if file.endswith(ext):
				return settings['mode.'+mode+'.mode_class']
	return DefaultMode

class DefaultMode:
	
	name = 'default'
	
	LEXER=stc.STC_LEX_NULL
	
	STYLE_ID_DEFAULT=0
	STYLE_ID_STRING=None
	STYLE_ID_COMMENT=None
	STYLE_ID_KEYWORD=None
	STYLE_ID_CLASSNAME=None
	STYLE_ID_METHODNAME=None
	STYLE_ID_DELIMETER=None
	STYLE_ID_NUMBER=None
	STYLE_ID_CHAR=None
	
	SECTION_PATTERNS = []
	
	@classmethod
	def _set_style_from_settings(cls,stc_instance,style_ids,prefix):
		if style_ids is None:
			return
			
		if not isSequenceType(style_ids):
			style_ids=[style_ids]
			
		spec = ''
		spec+='face:%s,'%settings[prefix+'.font']
		spec+='size:%s,'%settings[prefix+'.size']
		spec+='back:#%06x,'%settings[prefix+'.color_bg'].RGB
		spec+='fore:#%06x,'%settings[prefix+'.color_fg'].RGB
		if settings[prefix+'.bold']: spec += 'bold,'
		if settings[prefix+'.italic']: spec += 'italic,'

		#print prefix,spec

		for style_id in style_ids:
			stc_instance.StyleSetSpec(style_id,spec)
			
	@classmethod
	def style_stc(cls,stc_instance):
		stc_instance.SetLexer(cls.LEXER)

		stc_instance.SetKeyWords(0, settings['mode.' + cls.name + '.keywords'])

		cls._set_style_from_settings(stc_instance,stc.STC_STYLE_DEFAULT,'text.default') # need this here for whitespace		
		
		stc_instance.StyleClearAll()
		
		cls._set_style_from_settings(stc_instance,cls.STYLE_ID_DEFAULT,'text.default')
		cls._set_style_from_settings(stc_instance,cls.STYLE_ID_STRING,'text.string')
		cls._set_style_from_settings(stc_instance,cls.STYLE_ID_COMMENT,'text.comment')
		cls._set_style_from_settings(stc_instance,cls.STYLE_ID_KEYWORD,'text.keyword')
		stc_instance.StyleSetSpec(stc.STC_STYLE_LINENUMBER,  "back:#%06x"%settings['text.margin.colorbg'].RGB)

settings['mode.default.keywords']=''

class PythonMode(DefaultMode):
	name = "python"
	
	LEXER=stc.STC_LEX_PYTHON
	
	STYLE_ID_STRING=(stc.STC_P_STRING,stc.STC_P_CHARACTER,stc.STC_P_TRIPLE,stc.STC_P_TRIPLEDOUBLE)
	STYLE_ID_COMMENT=(stc.STC_P_COMMENTLINE,stc.STC_P_COMMENTBLOCK)
	STYLE_ID_KEYWORD=stc.STC_P_WORD
	STYLE_ID_CLASSNAME=stc.STC_P_CLASSNAME
	STYLE_ID_METHODNAME=stc.STC_P_DEFNAME
	STYLE_ID_DELIMETER=stc.STC_P_OPERATOR
	STYLE_ID_NUMBER=stc.STC_P_NUMBER
	
	SECTION_PATTERNS = ['\w.*:']

	
settings['available_modes'].append('python')
settings['mode.python.mode_class']=PythonMode
settings['mode.python.extensions']=['.py']
settings['mode.python.keywords'] = "and assert break class continue def del elif else except exec finally for from global if import in is lambda not or pass print raise return try while yield me"

	
class CMode(DefaultMode):
	name = "C"
	
	LEXER=stc.STC_LEX_CPP
	
	STYLE_ID_STRING=(stc.STC_C_CHARACTER,stc.STC_C_STRING)
	STYLE_ID_COMMENT=(stc.STC_C_COMMENT,stc.STC_C_COMMENTLINE,stc.STC_C_COMMENTDOC,stc.STC_C_COMMENTLINEDOC)
	STYLE_ID_KEYWORD=(stc.STC_C_WORD,stc.STC_C_WORD2)
	STYLE_ID_DELIMETER=stc.STC_C_OPERATOR
	STYLE_ID_NUMBER=stc.STC_C_NUMBER
	
	SECTION_PATTERNS = ['\w.*\(']

	
settings['available_modes'].append('C')
settings['mode.C.mode_class']=CMode
settings['mode.C.extensions']=['.c'] # .h assumed to be a C++ file, since its a superset anyway
settings['mode.C.keywords'] = "auto array bool break case char class complex ComplexInf ComplexNaN" \
	+" const continue default delete" \
	+" do double else enum export extern float for foreach goto if Inf inline int" \
	+" long namespace NaN new NULL private public register restrict return short" \
	+" signed sizeof static string_t struct switch this typedef union unsigned" \
	+" using void volatile wchar_t while __declspec" # ?? are these the right keywords? they come from cpp.properties> keywordclass.ch


class CSharpMode(CMode):
	name = "C#"

	
settings['available_modes'].append('C#')
settings['mode.C#.mode_class']=CSharpMode
settings['mode.C#.extensions']=['.cs']
settings['mode.C#.keywords'] = "abstract as base bool break byte case catch char checked class" \
	+" const continue decimal default delegate do double else enum" \
	+" event explicit extern false finally fixed float for foreach goto if" \
	+" implicit in int interface internal is lock long namespace new null" \
	+" object operator out override params private protected public" \
	+" readonly ref return sbyte sealed short sizeof stackalloc static" \
	+" string struct switch this throw true try typeof uint ulong" \
	+" unchecked unsafe ushort using virtual void while"
	
class CPPMode(CMode):
	name = "C++"

	
settings['available_modes'].append('C++')
settings['mode.C++.mode_class']=CSharpMode
settings['mode.C++.extensions']=".cc .cpp .cxx .hh .hpp .hxx .sma"
settings['mode.C++.keywords'] = "and and_eq asm auto bitand bitor bool break" \
	+" case catch char class compl const const_cast continue" \
	+" default delete do double dynamic_cast else enum explicit export extern false float for" \
	+" friend goto if inline int long mutable namespace new not not_eq" \
	+" operator or or_eq private protected public" \
	+" register reinterpret_cast return short signed sizeof static static_cast struct switch" \
	+" template this throw true try typedef typeid typename union unsigned using" \
	+" virtual void volatile wchar_t while xor xor_eq NULL"
